﻿// This file is part of VideoLan.Inteop
//
// Copyright (C) 2008, Michael Melendez, http://www.MeediOS.com
//
//VideoLan.Inteop is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either 
//version 2.1 of the License, or (at your option) any later version.
//
//VideoLan.Inteop is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public 
//License along with this library.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;

namespace VideoLan
{
    [Flags]
    internal enum ObjectSearchMode : int
    {
        FIND_PARENT = 0x0001,
        FIND_CHILD = 0x0002,
        FIND_ANYWHERE = 0x0003,
        FIND_STRICT = 0x0010,
    }

    internal enum ObjectType : int
    {
        VLC_OBJECT_LIBVLC = (-2),
        VLC_OBJECT_MODULE = (-3),
        VLC_OBJECT_INTF = (-4),
        VLC_OBJECT_PLAYLIST = (-5),
        VLC_OBJECT_INPUT = (-7),
        VLC_OBJECT_DECODER = (-8),
        VLC_OBJECT_VOUT = (-9),
        VLC_OBJECT_AOUT = (-10),
        VLC_OBJECT_PACKETIZER = (-13),
        VLC_OBJECT_ENCODER = (-14),
        VLC_OBJECT_ANNOUNCE = (-17),
        VLC_OBJECT_OPENGL = (-21),
        VLC_OBJECT_OSDMENU = (-28),
        VLC_OBJECT_GENERIC = (-666)
    }

    internal enum VlcError : int
    {
        VLC_SUCCESS = -0,
        VLC_ENOMEM = -1, 
        VLC_ETHREAD = -2, 
        VLC_ETIMEOUT = -3,
        VLC_ENOMOD = -10,
        VLC_ENOOBJ = -20,
        VLC_ENOVAR = -30,
        VLC_EBADVAR = -31,
        VLC_ENOITEM = -40,
        VLC_EEXIT = -255,
        VLC_EEXITSUCCESS = -999,
        VLC_EGENERIC = -666 
    }


    [StructLayout(LayoutKind.Explicit)]
    internal struct vlc_value_t
    {
        [FieldOffset(0)]
        public Int32 i_int;
        [FieldOffset(0)]
        public Int32 b_bool;
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.R4)]
        public float f_float;
        [FieldOffset(0)]
        public IntPtr psz_string;
        [FieldOffset(0)]
        public IntPtr p_address;
        [FieldOffset(0)]
        public IntPtr p_object;
        [FieldOffset(0)]
        public IntPtr p_list;
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.I8)]
        public Int64 i_time;
        [FieldOffset(0)]
        public IntPtr psz_name;
        [FieldOffset(4)]
        public Int32 i_object_id;
    }

    internal class VlcObject : IDisposable
    {
        private bool _disposed = false;
        private IntPtr p_vlc_oldapi_dont_use;

        internal VlcObject(int ObsoleteShouldNeverBeUsedOldApiAndCouldBreakAnyDayId)
        {
            p_vlc_oldapi_dont_use = vlc_current_object(ObsoleteShouldNeverBeUsedOldApiAndCouldBreakAnyDayId);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                _disposed = true;
                if (this.p_vlc_oldapi_dont_use != IntPtr.Zero)
                    __vlc_object_release(p_vlc_oldapi_dont_use);
            }
        }

        ~VlcObject()
        {
            Dispose(false);
        }


        public float GetVlcObjectFloat(ObjectType oType, String propertyName, float defaultValue)
        {
            IntPtr p_object = __vlc_object_find(p_vlc_oldapi_dont_use,  oType, ObjectSearchMode.FIND_CHILD);

            if ((p_object == IntPtr.Zero))
                throw new NullReferenceException(string.Format("{0} not found", oType));

            float rtn = defaultValue;
            vlc_value_t vlu = new vlc_value_t();
            if (VlcError.VLC_SUCCESS == __var_Get(p_object, propertyName, ref vlu))
                rtn = vlu.f_float;
            __vlc_object_release(p_object);
            return rtn;
        }

        public void SetVlcObjectFloat(ObjectType oType, String propertyName, float value)
        {
            IntPtr p_object = __vlc_object_find(p_vlc_oldapi_dont_use, oType, ObjectSearchMode.FIND_CHILD);

            if ((p_object == IntPtr.Zero))
                throw new NullReferenceException(string.Format("{0} not found", oType));

            vlc_value_t vlu = new vlc_value_t();
            vlu.f_float = value;
            if (VlcError.VLC_SUCCESS != __var_Set(p_object, propertyName, ref vlu))
                throw new Exception(string.Format("property '{0}' not set", propertyName));
            __vlc_object_release(p_object);
        }

        #region libvlc api
        [DllImport("libvlc")]
        private static extern IntPtr vlc_current_object(int i_object);

        [DllImport("libvlc")]
        private static extern IntPtr __vlc_object_find(IntPtr p_object, ObjectType objectType, ObjectSearchMode mode);

        [DllImport("libvlc")]
        private static extern VlcError __var_Get(IntPtr p_object, [MarshalAs(UnmanagedType.LPStr)] String name, ref vlc_value_t value);

        [DllImport("libvlc")]
        private static extern VlcError __var_Set(IntPtr p_object, [MarshalAs(UnmanagedType.LPStr)] String name, ref vlc_value_t value);

        [DllImport("libvlc")]
        private static extern void __vlc_object_release(IntPtr p_object);

        #endregion
    }
}